package com.ssm.web.config.exception;

import com.ssm.common.exception.BusinessException;
import com.ssm.common.restful.AjaxResult;
import com.ssm.common.restful.Result;
import com.ssm.common.restful.ResultGenerator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

/**
 * https://blog.csdn.net/f641385712/article/details/102294670
 * 对 springmvc 中的控制器抛出的异常进行处理
 * 在 spring 3.2 中新增 @ControllerAdvice 注解，用于定义 @ExceptionHandler、@InitBinder、@ModelAttribute，并应用到所有 @RequestMapping 中
 * 在 Controller 层统一对异常进行处理
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    // 会在 handleException 之前调用
    // @ModelAttribute(name = "subject")
    // public void subject() {
    //    System.out.println(SecurityUtils.getSubject());
    // }

    /**
     * 定制化处理 MethodArgumentNotValidException：入参验证异常
     */
    @Override
    public ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        BindingResult bindingResult = ex.getBindingResult();
        StringBuffer sb = new StringBuffer();
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            sb.append(fieldError.getDefaultMessage() + "/");
        }
        AjaxResult ajaxResult = AjaxResult.error(sb);

        status = HttpStatus.FORBIDDEN;

        return super.handleExceptionInternal(ex, ajaxResult, headers, status, request);
    }

    /**
     * 定制化处理 MethodArgumentNotValidException：入参验证异常
     */
    // @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public Result handleMethodArgumentNotValidException(HttpServletRequest req, MethodArgumentNotValidException e) {
        BindingResult bindingResult = e.getBindingResult();
        StringBuffer sb = new StringBuffer();
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            sb.append(fieldError.getDefaultMessage() + "/");
        }
        return ResultGenerator.genFailResult(sb.substring(0, sb.length() - 1));
    }

    /**
     * 定制化处理 HttpRequestMethodNotSupportedException 异常
     */
    @Override
    protected ResponseEntity<Object> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        if (log.isWarnEnabled()) {
            log.warn(ex.getMessage());
        }

        String method = ex.getMethod();
        String[] supportedMethods = ex.getSupportedMethods();

        AjaxResult ajaxResult = new AjaxResult(
                status.value(),
                "不支持的请求类型：" + method + "，支持的请求类型：" + Arrays.toString(supportedMethods),
                null);

        return super.handleExceptionInternal(ex, ajaxResult, headers, status, request);
    }

    /**
     * 兜底异常处理
     */
    // @ResponseStatus(HttpStatus.FORBIDDEN)
    // @ExceptionHandler(value = Exception.class)
    public Object defaultErrorHandler(Exception ex) {
        if (log.isInfoEnabled()) {
            log.error("Start handle exception,Exception message:" + ex);
        }
        if (ex instanceof BusinessException) {
            log.error("ex instanceof BusinessException");
        }
        return ResultGenerator.genFailResult(ex.getMessage());
    }
}
